package edu.umd.ion.wavemeter.client;

//import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.widgetideas.client.ProgressBar;

import edu.umd.ion.wavemeter.service.PIDSettings;
import edu.umd.ion.wavemeter.service.PIDSettingsInUse;
import edu.umd.ion.wavemeter.service.WavemeterChannelData;
import edu.umd.ion.wavemeter.service.WavemeterServiceAsync;


public class ChannelPIDWidget extends Composite {
	int ChannelNumber;
	WavemeterServiceAsync WavemeterService;
	PIDSettings PID = new PIDSettings();
	TextBox PBox=new TextBox(), IBox=new TextBox(), 
				 DBox=new TextBox(), TaBox=new TextBox(),
				 dtBox=new TextBox();
	SuggestBox CourseBox= new SuggestBox();
	CheckBox NegPol=new CheckBox("Invert"),
			 //EnableBox=new CheckBox("Enable"),
			 UseTa=new CheckBox("Use ta"),
			 Constantdt= new CheckBox("Constant dt"),
			 AutoClearHistory= new CheckBox("auto clear history");
	Label TaBoxLabel, dtBoxLabel;
	Button RefreshButton, ResetButton, ApplyButton, LockButton, UnlockButton;
	FlexTable MyTable = new FlexTable();
	DisclosurePanel Disclosure;
	ProgressBar VoltageIndicator;
	private HTML ErrorMessage;
	private boolean NeedsStyling = true;
	private static PIDSettingsInUse MyPIDSettingsInUse;
	
	private ProgressBar.TextFormatter VoltageTextFormatter = new  ProgressBar.TextFormatter() {
		protected String getText(ProgressBar bar, double curProgress)
		{
			return NumberFormat.getFormat("0000.0").format(curProgress)+" mV";
		}
	};
	
	private class MyFocusHandler implements FocusHandler {
		public void onFocus(FocusEvent event) {
			WavemeterService.getPIDCourseSuggestions(ChannelNumber, CourseSuggestCallback);
		}
	}
	
	// Callbacks	
	OpenHandler<DisclosurePanel> MyDisclosureHandler = new OpenHandler<DisclosurePanel>()
	{
		public void onOpen(OpenEvent<DisclosurePanel> event) {
			WavemeterService.getPID(ChannelNumber, PIDCallback);
			if (NeedsStyling) { styleMyself(); }
		}
	};
	
	ClickHandler Refresh = new ClickHandler() {
		public void onClick(ClickEvent e) {
			WavemeterService.getPID(ChannelNumber, PIDCallback);
		}
	};
	
	ClickHandler Clear = new ClickHandler() {
		public void onClick(ClickEvent e) {
			WavemeterService.clearPIDHistory(ChannelNumber, CommandCallback);
		}
	};

	ClickHandler LockPID = new ClickHandler() {
		public void onClick(ClickEvent e) {
			PID.LockEnabled = true;
			setPIDServer();
		}
	};

	ClickHandler UnlockPID = new ClickHandler() {
		public void onClick(ClickEvent e) {
			PID.LockEnabled = false;
			setPIDServer();
		}
	};

	ClickHandler Enable = new ClickHandler() {
		public void onClick(ClickEvent e) {
			if (AutoClearHistory.getValue())
				WavemeterService.clearPIDHistory(ChannelNumber,CommandCallback);
			PushPIDSettings.onClick(e);
			WavemeterService.getPID(ChannelNumber,PIDCallback);
		}
	};
	
	ClickHandler PushPIDSettings = new ClickHandler() {
		public void onClick(ClickEvent e) {
			setPIDServer();
		}
	};

	ClickHandler PushCourse = new ClickHandler() {
		public void onClick(ClickEvent e) {
			WavemeterService.setPIDCourse(ChannelNumber,CourseBox.getText(),PIDCourseCallback);
		}
	};
	
	private AsyncCallback<PIDSettings> PIDCallback = new AsyncCallback<PIDSettings>()
	{
		public void onFailure (Throwable caught)
		{
			try {
				ErrorMessage.setHTML( "PID: " + caught.getMessage() );
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}
		}
		public void onSuccess (PIDSettings PID)
		{
			setPID(PID);
			ErrorMessage.setHTML( "" );
		}
	};

	private AsyncCallback<String> PIDCourseCallback = new AsyncCallback<String>()
	{
		public void onFailure (Throwable caught)
		{
			try {
				ErrorMessage.setHTML( "PID Course: " + caught.getMessage() );
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}
		}
		public void onSuccess (String Course)
		{
			setPIDCourse(Course); 
			ErrorMessage.setHTML( "" );
		}
	};

	private AsyncCallback<Void> CommandCallback = new AsyncCallback<Void>() {
		public void onFailure(Throwable caught) {
			try {
				ErrorMessage.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}
		}

		public void onSuccess(Void result) {
			ErrorMessage.setHTML("");
		}
	};

	private AsyncCallback<String[]> CourseSuggestCallback = new AsyncCallback<String[]>() {
		public void onFailure(Throwable caught) {
			try {
				ErrorMessage.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}
		}

		public void onSuccess(String[] result) {
			MultiWordSuggestOracle oracle = (MultiWordSuggestOracle) CourseBox.getSuggestOracle();
			for (int i=0; i<result.length; ++i) {
				oracle.add(result[i]);
			}
		}
	};

	private AsyncCallback<PIDSettingsInUse> PIDSettingsInUseCallback = new AsyncCallback<PIDSettingsInUse>() {
		public void onFailure(Throwable caught) {
			try {
				ErrorMessage.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
				reload();
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}
		}

		public void onSuccess(PIDSettingsInUse result) {
			MyPIDSettingsInUse = result;	
			applyPIDSettingsInUse();
		}

	};
	
	private native void reload() /*-{
    $wnd.location.reload();
   }-*/;

	public void setPIDServer() {
		PID.Channel = ChannelNumber;
		PID.P = Double.parseDouble( PBox.getText() );
		PID.I = Double.parseDouble( IBox.getText() );
		PID.D = Double.parseDouble( DBox.getText() );
		PID.Ta = Double.parseDouble( TaBox.getText() );
		PID.dt = Double.parseDouble( dtBox.getText() );
		PID.Polarity = NegPol.getValue();
		PID.UseTa = UseTa.getValue();
		PID.Course = CourseBox.getText();
		PID.AutoClearHistory = AutoClearHistory.getValue();
		PID.Constantdt = Constantdt.getValue();
		WavemeterService.setPID(PID,PIDCallback);
	}
	
	public void setPIDCourse( String Course )
	{
		CourseBox.setText( Course );	
	}
	
	public void setPID( PIDSettings data )
	{
		NumberFormat Formatter = NumberFormat.getFormat("0.000");
		PID = data;
		PBox.setText( Formatter.format(PID.P));
		IBox.setText( Formatter.format(PID.I));
		DBox.setText( Formatter.format(PID.D));
		TaBox.setText( Formatter.format(PID.Ta));
		dtBox.setText( Formatter.format(PID.dt));
		CourseBox.setText( PID.Course );
		NegPol.setValue( PID.Polarity );
		//EnableBox.setValue( PID.LockEnabled );
		UseTa.setValue( PID.UseTa );
		Constantdt.setValue( PID.Constantdt );
		AutoClearHistory.setValue( PID.AutoClearHistory );
		PID = data;
	}
	
	public void set(WavemeterChannelData Data) {
		VoltageIndicator.setProgress(Data.AOVoltage);
		if (Data.PIDSettingsSerial>PID.Serial) {
			WavemeterService.getPID(ChannelNumber, PIDCallback);
		}
	}
	
	public void styleMyself() {
		NeedsStyling = false;
		String ButtonSize = ResetButton.getOffsetWidth()+"px";
		RefreshButton.setWidth(ButtonSize);
		ApplyButton.setWidth(ButtonSize);
		LockButton.setWidth(ButtonSize);
		UnlockButton.setWidth(ButtonSize);
		applyPIDSettingsInUse();
	}

	public void applyPIDSettingsInUse() {
		if (MyPIDSettingsInUse!=null) {
			UseTa.setVisible( MyPIDSettingsInUse.IsUsed_UseTa );
			Constantdt.setVisible(  MyPIDSettingsInUse.IsUsed_Constantdt );
			TaBox.setVisible( MyPIDSettingsInUse.IsUsed_Ta );
			TaBoxLabel.setVisible( MyPIDSettingsInUse.IsUsed_Ta );
			dtBox.setVisible( MyPIDSettingsInUse.IsUsed_dt );
			dtBoxLabel.setVisible( MyPIDSettingsInUse.IsUsed_dt );
		} 
	}
	
	public ChannelPIDWidget(WavemeterServiceAsync wavemeter, int channel, Panel ErrorPanel)
	{		
		ErrorMessage = new HTML();
		ErrorPanel.add( ErrorMessage );
		WavemeterService = wavemeter;
		ChannelNumber = channel;
		RefreshButton = new Button("Refresh",Refresh);
		ResetButton = new Button("Clear PID",Clear);
		ApplyButton = new Button("Apply",PushPIDSettings);
		LockButton = new Button("Lock",LockPID);
		UnlockButton = new Button("Unlock",UnlockPID);
		PBox.setStylePrimaryName("gwt-TextBox-PID");
		PBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushPIDSettings) );
		IBox.setStylePrimaryName("gwt-TextBox-PID");
		IBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushPIDSettings) );
		DBox.setStylePrimaryName("gwt-TextBox-PID");
		DBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushPIDSettings) );
		TaBox.setStylePrimaryName("gwt-TextBox-PID");
		TaBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushPIDSettings) );
		dtBox.setStylePrimaryName("gwt-TextBox-PID");
		dtBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushPIDSettings) );
		
		CourseBox.setStylePrimaryName("gwt-TextBox-PID");
		CourseBox.addKeyPressHandler(new Keyboard(this.PushCourse));
		
		TaBoxLabel = new Label("ta");
		dtBoxLabel = new Label("dt");
		MyTable.setText(0,0,"P");
		MyTable.setWidget(0,1, PBox );
		MyTable.setText(0,2,"I");
		MyTable.setWidget(0,3, IBox );
		MyTable.setText(0,4, "D");
		MyTable.setWidget(0,5, DBox );
		MyTable.setWidget(0,6, TaBoxLabel);
		MyTable.setWidget(0,7, TaBox );
		MyTable.setWidget(0,8, dtBoxLabel);
		MyTable.setWidget(0,9, dtBox );
		
		NegPol.addClickHandler(this.PushPIDSettings);
		MyTable.setWidget(0,10, NegPol );
		UseTa.addClickHandler(this.PushPIDSettings);
		MyTable.setWidget(0,11, UseTa );
		Constantdt.addClickHandler(this.PushPIDSettings);
		MyTable.setWidget(0, 12, Constantdt );
		AutoClearHistory.addClickHandler(this.PushPIDSettings);
		MyTable.setWidget(0, 13, AutoClearHistory );
		if (MyPIDSettingsInUse==null) {
			WavemeterService.getPIDSettingsInUse(PIDSettingsInUseCallback);
		}

		FlexTable.FlexCellFormatter Formatter = MyTable.getFlexCellFormatter();
		Formatter.setColSpan(1, 0, 2);
		MyTable.setWidget(1,0, RefreshButton );
		Formatter.setColSpan(1, 1, 2);
		MyTable.setWidget(1,1, ApplyButton);
		Formatter.setColSpan(1, 2, 2);
		MyTable.setWidget(1,2, ResetButton);
		Formatter.setColSpan(1, 3, 2);
		MyTable.setWidget(1,3, LockButton);
		Formatter.setColSpan(1, 4, 2);
		MyTable.setWidget(1,4, UnlockButton);
		
		CourseBox.setWidth("100%");
		CourseBox.getTextBox().addFocusHandler(new MyFocusHandler());
		MyTable.setWidget(2,0, CourseBox );
		Formatter.setColSpan(2,0,14);
		
		VoltageIndicator = new ProgressBar(-10000,10000,0,VoltageTextFormatter);
		VoltageIndicator.setWidth("300px");
		
		HorizontalPanel PIDHeader = new HorizontalPanel();
		PIDHeader.add(new Label("PID")); 
		PIDHeader.add(VoltageIndicator);
		
		MyTable.setWidth("100%");
		Disclosure = new DisclosurePanel();
		Disclosure.setHeader(PIDHeader);
		Disclosure.add(MyTable);
		Disclosure.addOpenHandler(MyDisclosureHandler);
		initWidget(Disclosure);
	}
}
